iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0
自我挑戰組

實驗室助理的技術文章自我整理系列 第 21

Python - Python Selenium 套件使用參考筆記

  • 分享至 

  • xImage
  •  

Python - Python Selenium 套件使用參考筆記

參考資料

說明

當初會寫這篇參考筆記,主要是因為, Selenium-Python 的中文文件,看起來應該是大陸人翻譯的,只有簡體中文,沒有繁體中文的版本,所以我就自己整理了繁體中文的版本,再把裡面的大陸用語轉換成台灣用語(先說我不是專業的,用詞錯誤請不要噴我w),增加或刪減一些文字,以方便肉眼閱讀XD。

特此撰寫本篇文章作為紀錄文件,用以方便後續有需要的時候,可以快速的重複查閱,雖然後面比較沒有什麼機會再用到,但也算是一個還不錯的經驗。

安裝Selenium

指令如下:

pip3 install selenium

下載與安裝 Chrome Driver

請前往下方連結,下載對應版本的 Chrome Driver,並將壓縮檔內的chromedriver.exe解壓縮到指定的工作目錄。
ChromeDriver - WebDriver for Chrome

使用 Selenium 開啟 Chrome 瀏覽器

開啟 Chrome 瀏覽器,並前往 Google 搜尋頁面,然後再關閉瀏覽器,程式碼如下:

from selenium import webdriver
driver = webdriver.Chrome('chromedriver.exe')
driver.get('https://www.google.com')
driver.close()

使用 Selenium 查找元素定位

通過 Class name 定位元素

當你通過 class name 查找元素時可使用這個。在該策略下,頁面中第一個匹配該 class 屬性的元素會被匹配並返回。如果找不到任何元素,則會拋出 NoSuchElementException 異常。

driver.find_element_by_class_name('class name')

通過CSS選擇器查找元素

當你通過CSS選擇器查找元素時可以使用這個。在該策略下,頁面中第一個匹配該 CSS 選擇器的元素會被匹配並返回。如果找不到任何元素,則會拋出 NoSuchElementException 異常。

driver.find_element_by_css_selector('css selector')

通過 ID 查找元素

當你知道一個元素的 id 時,你可以使用本方法。在該策略下,頁面中第一個符合該 id 的元素會被匹配並返回。如果找不到任何元素,會拋出 NoSuchElementException 異常。

driver.find_element_by_id('id')

通過連結文字查找元素

當你知道在一個連結標籤中使用的文字時可使用這個。在該策略下,頁面中第一個匹配連結文字的標籤會被匹配並返回。如果找不到任何元素,則會拋出 NoSuchElementException 異常。

driver.find_element_by_link_text('link text')

也可以只用連結的部分文字定位元素:

driver.find_element_by_partial_link_text('partial link text')

通過 Name 查找元素

當你知道一個元素的 name 時,你可以使用本方法。在該策略下,頁面中第一個該 name 元素會被匹配並返回。如果找不到任何元素,會拋出 NoSuchElementException 異常。

driver.find_element_by_name('name')

通過標籤名 tag 查找元素

當你通過標籤名 tag 查找元素時可使用這個。在該策略下,頁面中第一個匹配該標籤名的元素 會被匹配並返回。如果找不到任何元素,會拋出 NoSuchElementException 異常。

driver.find_element_by_tag_name('tag')

通過XPath查找元素

XPath是XML文檔中查找結點的語法。因為HTML文檔也可以被轉換成XML(XHTML)文檔, Selenium的用戶可以利用這種強大的語言在web應用中查找元素。 XPath擴展了(當然也支持)這種通過id或name屬性獲取元素的簡單方式,同時也開闢了各種新的可能性, 例如獲取頁面上的第三個複選框。

使用XPath的主要原因之一就是當你想獲取一個既沒有id屬性也沒有name屬性的元素時, 你可以通過XPath使用元素的絕對位置來獲取他(這是不推薦的),或相對於有一個id或name屬性的元素(理論上的父元素)的來獲取你想要的元素。 XPath定位器也可以通過非id和name屬性查找元素。

絕對的XPath是所有元素都從根元素的位置(HTML)開始定位,只要應用中有輕微的調整,會就導致你的定位失敗。但是通過就近的包含id或者name屬性的元素出發定位你的元素,這樣相對關係就很靠譜, 因為這種位置關係很少改變,所以可以使你的測試更加強大。

driver.find_element_by_xpath('//*[@id="lst-ib"]')

使用 Selenium 操作網頁元素

開啟 Chrome 瀏覽器,並前往 Google 搜尋頁面,然後搜尋"你好"並按下 Enter,程式碼如下:

from selenium import webdriver
driver = webdriver.Chrome('chromedriver.exe')
driver.get('https://www.google.com')
q  = driver.find_element_by_name('q')

q.send_keys('你好')

from selenium.webdriver.common.keys import Keys
q.send_keys(Keys.RETURN)

開啟 Chrome 瀏覽器,並前往 Google 搜尋頁面,然後點擊登入按鈕,程式碼如下:

from selenium import webdriver
driver = webdriver.Chrome('chromedriver.exe')
driver.get('https://www.google.com')

login = driver.find_element_by_link_text('登入')

login.click()

使用 Selenium 操作 frame 標籤中的元素

很多人在用selenium定位頁面元素的時候會遇到定位不到的問題,明明元素就在那兒,就是定位不到,這種情況很有可能是frame 在搞鬼(可能原因之一),可以去仔細看看你網頁的DOM樹!

frame標籤有framesetframeiframe三種,frameset跟其他普通標籤沒有區別,不會影響到正常的定位,而frame與iframe對selenium定位而言是一樣的,selenium有一組方法對frame進行操作:

driver.switch_to.frame(reference)  # 切到指定frame,可用id或name(str)、index(int)、元素(WebElement)定位
driver.switch_to.parent_frame()  # 切到父级frame,如果已是主文档,则无效果
driver.switch_to.default_content()  # 切到主文档,DOM树最开始的<html>标签

1. 怎麼切到frame中(switch_to.frame())

selenium提供了switch_to.frame()方法來切換frame

switch_to.frame(reference)

reference是傳入的參數,用來定位frame,可以傳入id、name、index以及selenium的WebElement對象,假設有如下HTML代碼 index.html:

<html lang="en">
<head>
    <title>FrameTest</title>
</head>
<body>
<iframe src="a.html" id="frame1" name="myframe"></iframe>
</body>
</html>

想要定位其中的iframe並切進去,可以通過如下代碼:

from selenium import webdriver
driver = webdriver.Firefox()
driver.switch_to.frame(0)  # 1.用frame的index来定位,第一个是0
# driver.switch_to.frame("frame1")  # 2.用id来定位
# driver.switch_to.frame("myframe")  # 3.用name来定位
# driver.switch_to.frame(driver.find_element_by_tag_name("iframe"))  # 4.用WebElement对象来定位

通常採用id和name就能夠解決絕大多數問題。但有時候frame並無這兩項屬性,則可以用index和WebElement來定位:

  • index從0開始,傳入整型參數即判定為用index定位,傳入str參數則判定為用id/name定位
  • WebElement對象,即用find_element系列方法所取得的對象,我們可以用tag_name、xpath等來定位frame對象

舉個例子:

<iframe src="myframetest.html" />

用xpath定位,傳入 WebElement 物件:

driver.switch_to.frame(driver.find_element_by_xpath("//iframe[contains(@src,'myframe')]"))

2. 從frame中切回主文檔(switch_to.default_content())

切到frame中之後,我們便不能繼續操作主文檔的元素,這時如果想操作主文檔內容,則需切回主文檔。

driver.switch_to.default_content()

3. 嵌套frame的操作(switch_to.parent_frame())

有時候我們會遇到嵌套的frame,如下:

<html>
	<iframe id="frame1">
		<iframe id="frame2" / >
	</iframe>
</html>
  1. 從主文檔切到frame2,一層層切進去
driver.switch_to.frame("frame1")  # 先切到frame1
driver.switch_to.frame("frame2")  # 再切到frame2
  1. 從frame2再切回frame1,這裡selenium給我們提供了一個方法能夠從子frame切回到父frame,而不用我們切回主文檔再切進來。
driver.switch_to.parent_frame()  # 如果目前已是主文檔,則無效果

有了parent_frame()這個相當於後退的方法,我們可以隨意切換不同的frame,隨意的跳來跳去了。

所以只要善用以下三個方法,遇到frame分分鐘搞定:

driver.switch_to.frame(reference)
driver.switch_to.parent_frame()
driver.switch_to.default_content()

使用 Selenium 滾動網頁捲軸(scrollBar)

參考:Python Selenium控制网页滚动条缓慢滚动

通過driver.execute()執行js代碼,達到目的。

driver.execute_script('window.scrollBy(0,1000)')

scrollBy(x,y)中,x為必須參數,表示向右滾動的像素值;y也為必須參數,表示向下滾動的像素值

driver.execute_script('window.scrollTo(0,1000)')

scrollTo(x,y) 中,x為必要參數,表示要在窗口文檔顯示區左上角顯示的文檔的x坐標;y也為必要參數,表示要在窗口文檔顯示區左上角顯示的文檔的y坐標

捲軸長度獲取

參考:.body.scrollHeight doesn't work in Firefox

可以在 Chrome 的監控視窗的Console 下指令取得。
兩個指令皆可使用,但在某些網站(如:Youtube)這兩個指令,可能會有其中一個失效。

document.body.scrollHeight
document.documentElement.scrollHeight

selenium 捲軸拉到底:

方法一:

driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')

方法二:

driver.execute_script('window.scrollTo(0,document.documentElement.scrollHeight)')

上一篇
Python - Python num2words 套件 - 將數字轉換為多種語言的單詞 - 參考筆記
下一篇
Python - Scrabble Word Finder - Python 爬蟲練習筆記
系列文
實驗室助理的技術文章自我整理30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言